package jsu.blogger;

import jsu.blogger.config.RedisKeyPrefixConfig;
import jsu.blogger.service.inter.UserFollowService;
import org.junit.jupiter.api.Test;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.RedisSystemException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;

import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@MapperScan("jsu.blogger.mapper")
public class testFollowService {
    @Autowired
    private UserFollowService userFollowService;

    @Test
    void testGetUserFollowList() {
        //userFollowService.getUserFollowersList(1L)
        System.out.println(userFollowService.getUserFollowListByRedis(1L));
    }
    @Test
    void testGetUserFollowListByRedis() throws InterruptedException {
        // 模拟并发访问的线程数
        int threadCount = 50; // 50个线程并发访问
        ExecutorService executorService = Executors.newFixedThreadPool(threadCount);
        CountDownLatch latch = new CountDownLatch(threadCount);

        // 用于记录每个线程的执行时间
        List<Long> executionTimes = new ArrayList<>();
        // 用于存储每个线程返回的数据
        List<Set<Long>> results = new ArrayList<>();

        // 模拟线程执行
        for (int i = 0; i < threadCount; i++) {
            executorService.submit(() -> {
                long startTime = System.currentTimeMillis();  // 获取开始时间
                Set<Long> result = null;
                try {
                    // 调用目标方法获取关注列表
                    result = userFollowService.getUserFollowListByRedis(1L);
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    long endTime = System.currentTimeMillis();  // 获取结束时间
                    long executionTime = endTime - startTime;  // 计算执行时间
                    executionTimes.add(executionTime);  // 保存执行时间
                    results.add(result); // 保存返回的数据
                    latch.countDown(); // 计数器减一
                }
            });
        }
        //System.out.println("时间"+executionTimes);
        // 等待所有线程执行完成
        latch.await();

        // 打印每个线程的执行时间
        System.out.println("每个线程的执行时间（毫秒）:");
        for (int i = 0; i < executionTimes.size(); i++) {
            System.out.println("线程 " + (i + 1) + " 执行时间: " + executionTimes.get(i) + " ms");
        }

        // 打印总的执行时间
        System.out.println("所有线程执行完毕，测试结束");

        // 计算总时间
        long totalTime = executionTimes.stream().mapToLong(Long::longValue).sum();
        System.out.println("总执行时间: " + totalTime + " ms");

        // 打印平均执行时间
        long averageTime = totalTime / executionTimes.size();
        System.out.println("平均执行时间: " + averageTime + " ms");

        // 打印每个线程返回的数据
        System.out.println("每个线程的返回数据（关注列表）:");
        for (int i = 0; i < results.size(); i++) {
            System.out.println("线程 " + (i + 1) + " 返回的关注列表: " + results.get(i));
        }

        // 关闭线程池
        executorService.shutdown();
    }

    @Test
    void testFollow(){

        userFollowService.followUser(2L,1L);
        userFollowService.followUser(2L,3L);
        userFollowService.followUser(2L,4L);
    }

    @Test
    void testUnFollow() throws InterruptedException {
        // 模拟并发访问的线程数
        int threadCount = 50; // 50个线程并发访问
        ExecutorService executorService = Executors.newFixedThreadPool(threadCount);
        CountDownLatch latch = new CountDownLatch(threadCount);

        // 用于记录每个线程的执行时间
        List<Long> executionTimes = new ArrayList<>();
        // 用于存储每个线程返回的数据
        List<Set<Long>> results = new ArrayList<>();

        // 模拟线程执行
        for (int i = 0; i < threadCount; i++) {
            executorService.submit(() -> {
                long startTime = System.currentTimeMillis();  // 获取开始时间
                Set<Long> result = null;
                try {
                    // 调用目标方法获取关注列
                   userFollowService.followUser(1L,2L);
                    userFollowService.unfollowUser(2L,1L);
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    long endTime = System.currentTimeMillis();  // 获取结束时间
                    long executionTime = endTime - startTime;  // 计算执行时间
                    executionTimes.add(executionTime);  // 保存执行时间
                    results.add(result); // 保存返回的数据
                    latch.countDown(); // 计数器减一
                }
            });
        }
        //System.out.println("时间"+executionTimes);
        // 等待所有线程执行完成
        latch.await();

        // 打印每个线程的执行时间
        System.out.println("每个线程的执行时间（毫秒）:");
        for (int i = 0; i < executionTimes.size(); i++) {
            System.out.println("线程 " + (i + 1) + " 执行时间: " + executionTimes.get(i) + " ms");
        }

        // 打印总的执行时间
        System.out.println("所有线程执行完毕，测试结束");

        // 计算总时间
        long totalTime = executionTimes.stream().mapToLong(Long::longValue).sum();
        System.out.println("总执行时间: " + totalTime + " ms");

        // 打印平均执行时间
        long averageTime = totalTime / executionTimes.size();
        System.out.println("平均执行时间: " + averageTime + " ms");

        // 打印每个线程返回的数据
        System.out.println("每个线程的返回数据（关注列表）:");
        for (int i = 0; i < results.size(); i++) {
            System.out.println("线程 " + (i + 1) + " 返回的关注列表: " + results.get(i));
        }

        // 关闭线程池
        executorService.shutdown();

    }

    @Test
    void testDecrementLikeCountWithLua(){

        decrementLikeCountWithLua(2L);
    }
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    public boolean decrementLikeCountWithLua(Long postId) {
        String blogKey = RedisKeyPrefixConfig.BLOG_HASH_KEY_PREFIX + postId;

        System.out.println("键是否存在 "+redisTemplate.hasKey(blogKey));
        String luaScript =
                "local likesCount = redis.call('HGET', KEYS[1], 'likesCount') " +
                        "return likesCount";

        try {
            List<Object> resultList = redisTemplate.execute(
                    new DefaultRedisScript<>(luaScript, List.class),
                    Collections.singletonList(blogKey)
            );

            if (resultList != null && !resultList.isEmpty()) {
                Object result = resultList.get(0);
                System.out.println(result);
                if (result instanceof Map) {
                    Map<String, Object> resultMap = (Map<String, Object>) result;
                    if (resultMap.containsKey("err")) {
                       // logger.error("Redis error: {}", resultMap.get("err"));
                        return false; // 返回 false，表示操作失败
                    }
                } else {
                    //logger.info("Redis script executed successfully, result: {}", result);
                    return true;
                }
            }
        } catch (RedisSystemException e) {
            throw  e;
            //logger.error("Error executing Redis Lua script", e);
           // return false;
        }
        return false;
    }

}

